<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>原生JS - 模拟 - 双向数据绑定</title>
</head>
<body>
    <!-- v-model 用于表单标签 -->
    <input type="text" id="myInp" oninput="inputChange(event)">
    <script>
        // new Vue({
        //     el: "#app",
        //     data: {
        //         msg: '你好啊'
        //     }
        // })
        // 前提: 咱们是模拟, 不是真正的vue源码

        let data = { // 类似于vue变量
            msg: "你好啊"
        }

        let $data = { // vue内部会把你 data对象 拷贝出来一份(内部使用) -肯定和上面一样
            msg: "你好啊"
        } 
        // 问题1: 为什么必须有一个相同的对象
        // 防止Object.defineProperty里递归

        // 1. 监测页面值的改变(oninput/onchange)
        function inputChange(ev){
            // (关键): 页面改变 -> 输入框的值 -> 变量  (视图 -> 变量)
            data.msg = ev.target.value // 触发下面set执行
        }
        // 2. 监听变量的改变(对象属性的改变)
        // 参数1: 要监听的对象, 参数2: 监听的属性名, 参数3: 监听的配置对象
        // 问题2: 自己实现了data.msg属性取值和赋值的过程
        Object.defineProperty(data, 'msg', { 
            set(val){ // 给data.msg = 值 就会触发这个函数
                $data.msg = val // 同步上去(为了一会儿下面取值)
                // 对data变量使用的地方更新
                document.getElementById("myInp").value = $data.msg;
            },
            get(){ // 当需要使用data.msg的值时, 触发此函数, 必须return给使用者一个值
                return $data.msg;
            }
        })
        console.log(data.msg);
        // 注意: 不要再get()里执行data.msg 会发生递归死循环

        // 总结:
        // v-model实现原理:
        // 视图 -> 数据  (监测标签的input事件), 把新的值赋予给vue变量
        // 视图 -> input事件 -> vue数据层
        // 视图 <- 数据  (Object.defineProperty) - vue2.x实现原理 

        // Vue3.x - Proxy(ES6新出的技术) - 深层

    </script>
</body>
</html>